package com.apes.framework.plugin.fileserver.repository.gridFs;


import com.apes.framework.plugin.fileserver.domain.File;
import com.mongodb.client.gridfs.GridFSFindIterable;
import com.mongodb.client.gridfs.model.GridFSFile;
import com.mongodb.client.result.UpdateResult;
import org.bson.Document;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.mongodb.gridfs.GridFsResource;
import org.springframework.data.mongodb.gridfs.GridFsTemplate;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 功能：GridFs File 存储库
 *
 * @author xul
 * @create 2018-05-25 14:38
 */
@Component
public class GridFsRepository {

    @Autowired
    private GridFsTemplate gridFsTemplate;

    @Autowired
    private MongoTemplate mongoTemplate;

    public File save(File file) {
        Document document = new Document();
        document.put("status", file.getStatus());
        ObjectId id = gridFsTemplate.store(new ByteArrayInputStream(file.getContent()), file.getName(), file.getContentType(), document);
        return findOne(id.toHexString());
    }

    public boolean updateFileStatus(String id, int status) {
        Query query = Query.query(Criteria.where("_id").is(new ObjectId(id)));
        Update update = Update.update("status", status);
        UpdateResult result = mongoTemplate.updateFirst(query, update, "fs.files");
        return result.getModifiedCount() == 1;
    }

    public boolean updateFileName(String id, String fileName) {
        Query query = Query.query(Criteria.where("_id").is(new ObjectId(id)));
        Update update = Update.update("filename", fileName);
        UpdateResult result = mongoTemplate.updateFirst(query, update, "fs.files");
        return result.getModifiedCount() == 1;
    }

    public void delete(String id) {
        Query query = Query.query(Criteria.where("_id").is(new ObjectId(id)));
        gridFsTemplate.delete(query);
    }

    public File findOne(String id) {
        GridFSFile file = findById(id);
        return toFile(file);
    }

    public Page<File> findAll(Pageable pageable) {
        GridFSFindIterable dbFiles = gridFsTemplate.find(new Query().with(pageable));
        List<File> files = dbFiles.map(this::toFile).into(new ArrayList<>());
        return new PageImpl(files, pageable, files.size());
    }

    public File findFirstByMd5(String md5) {
        Query query = Query.query(Criteria.where("md5").is(md5));
        GridFSFile file = gridFsTemplate.findOne(query);
        return toFile(file);
    }

    public GridFSFile findById(String id) {
        Query query;
        try {
            query = Query.query(Criteria.where("_id").is(new ObjectId(id)));
        } catch (Exception e) {
            throw new RuntimeException("文件：" + id + " 在服务器中不存在！");
        }
        GridFSFile file = gridFsTemplate.findOne(query);
        return file;
    }

    public File toFile(GridFSFile gridFile) {
        try {
            if (gridFile == null) {
                return null;
            }
            GridFsResource resource = gridFsTemplate.getResource(gridFile);
            ByteArrayOutputStream os = writeTo(resource.getInputStream());
            File file = new File(resource.getFilename(), resource.getContentType(), resource.contentLength(), os.toByteArray());
            file.setId((gridFile.getObjectId()).toHexString());
            file.setMd5(gridFile.getMD5());
            file.setUploadDate(gridFile.getUploadDate());
            Document document = gridFile.getMetadata() != null ? gridFile.getMetadata() : gridFile.getExtraElements();
            if (document != null) {
                file.setStatus((Integer) document.get("status"));
            }
            return file;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public ByteArrayOutputStream writeTo(InputStream in) throws Exception {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        int ch;
        while ((ch = in.read()) != -1) {
            os.write(ch);
        }
        return os;
    }
}
